package net.sf.midollo.lock;

public class SupplierConsumerLock {

  public static final int EMPTY = 0;
  public static final int DATA = 1;
  public static final int READ = 3;
  public static final int WRITE = 5;

  private int status = EMPTY;
  private final Object lock;

  public SupplierConsumerLock() {
    this.lock = this;
  }

  public SupplierConsumerLock(Object lock) {
    this.lock = lock;
  }

  public int getStatus() {
    synchronized (this.lock) {
      return this.status;
    }
  }

  public void readLock() throws InterruptedException {
    synchronized (this.lock) {
      while (this.status != DATA)
        wait();
      this.status = READ;
    }
  }

  public boolean readLock(long timeout) throws InterruptedException {
    synchronized (this.lock) {
      if (this.status != DATA) {
        wait(timeout);
        if (this.status != DATA)
          return false;
      }
      this.status = READ;
      return true;
    }
  }

  public void writeLock() throws InterruptedException {
    synchronized (this.lock) {
      while (this.status != EMPTY)
        wait();
      this.status = WRITE;
    }
  }

  public boolean writeLock(long timeout) throws InterruptedException {
    synchronized (this.lock) {
      if (this.status != EMPTY) {
        wait(timeout);
        if (this.status != EMPTY)
          return false;
      }
      this.status = WRITE;
      return true;
    }
  }

  public void readUnlock() {
    synchronized (this.lock) {
      if (this.status == READ) {
        this.status = EMPTY;
        notifyAll();
      }
    }
  }

  public void writeUnlock() {
    synchronized (this.lock) {
      if (this.status == WRITE) {
        this.status = DATA;
        notifyAll();
      }
    }
  }
}
